using System.Threading;

//
// * Copyright (c) 2002-2009 "Neo Technology,"
// *     Network Engine for Objects in Lund AB [http://neotechnology.com]
// *
// * This file is part of Neo4j.
// * 
// * Neo4j is free software: you can redistribute it and/or modify
// * it under the terms of the GNU Affero General Public License as
// * published by the Free Software Foundation, either version 3 of the
// * License, or (at your option) any later version.
// * 
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU Affero General Public License for more details.
// * 
// * You should have received a copy of the GNU Affero General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
// 
namespace org.neo4j.kernel.impl.core
{


	using DynamicRelationshipType = org.neo4j.graphdb.DynamicRelationshipType;
	using Node = org.neo4j.graphdb.Node;
	using PropertyContainer = org.neo4j.graphdb.PropertyContainer;
	using Relationship = org.neo4j.graphdb.Relationship;
	using Transaction = org.neo4j.graphdb.Transaction;
	using AbstractNeo4jTestCase = org.neo4j.kernel.impl.AbstractNeo4jTestCase;

	public class TestIsolation : AbstractNeo4jTestCase
	{
		public TestIsolation(string testName) : base(testName)
		{
		}

		public override void setUp()
		{
			base.setUp();
		}

		public override void tearDown()
		{
			base.tearDown();
		}

		public virtual void testSimpleTransactionIsolation()
		{
			commit();
//JAVA TO VB & C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final CountDownLatch latch1 = new CountDownLatch(1);
			CountDownLatch latch1 = new CountDownLatch(1);
//JAVA TO VB & C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final CountDownLatch latch2 = new CountDownLatch(1);
			CountDownLatch latch2 = new CountDownLatch(1);
			Transaction tx = getGraphDb().beginTx();
			Node n1, n2;
			Relationship r1;
			try
			{
				n1 = getGraphDb().createNode();
				n2 = getGraphDb().createNode();
				r1 = n1.createRelationshipTo(n2, DynamicRelationshipType.withName("TEST"));
				tx.success();
			}
			finally
			{
				tx.finish();
			}
//JAVA TO VB & C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final Node node1 = n1;
			Node node1 = n1;
//JAVA TO VB & C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final Node node2 = n2;
			Node node2 = n2;
//JAVA TO VB & C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final Relationship rel1 = r1;
			Relationship rel1 = r1;
			tx = getGraphDb().beginTx();
			try
			{
				node1.setProperty("key", "old");
				rel1.setProperty("key", "old");
				tx.success();
			}
			finally
			{
				tx.finish();
			}
			assertPropertyEqual(node1, "key", "old");
			assertPropertyEqual(rel1, "key", "old");
			assertRelationshipCount(node1, 1);
			assertRelationshipCount(node2, 1);
					// no tx.success();
			Thread t1 = new Thread(new Runnable() { public void run() { Transaction tx = getGraphDb().beginTx(); try { node1.setProperty("key", "new"); rel1.setProperty("key", "new"); node1.createRelationshipTo(node2, DynamicRelationshipType.withName("TEST")); assertPropertyEqual(node1, "key", "new"); assertPropertyEqual(rel1, "key", "new"); assertRelationshipCount(node1, 2); assertRelationshipCount(node2, 2); latch1.countDown(); latch2.await(); assertPropertyEqual(node1, "key", "new"); assertPropertyEqual(rel1, "key", "new"); assertRelationshipCount(node1, 2); assertRelationshipCount(node2, 2); } catch (InterruptedException e) { e.printStackTrace(); Thread.interrupted(); } finally { tx.finish(); assertPropertyEqual(node1, "key", "old"); assertPropertyEqual(rel1, "key", "old"); assertRelationshipCount(node1, 1); assertRelationshipCount(node2, 1); } } });
			t1.Start();
			try
			{
				latch1.await();
			}
			catch (InterruptedException e)
			{
				Thread.interrupted();
			}

			assertPropertyEqual(node1, "key", "old");
			assertPropertyEqual(rel1, "key", "old");
			assertRelationshipCount(node1, 1);
			assertRelationshipCount(node2, 1);

			latch2.countDown();
			try
			{
				t1.Join();
			}
			catch (InterruptedException e)
			{
				Thread.interrupted();
			}
			assertPropertyEqual(node1, "key", "old");
			assertPropertyEqual(rel1, "key", "old");
			assertRelationshipCount(node1, 1);
			assertRelationshipCount(node2, 1);

			tx = getGraphDb().beginTx();
			try
			{
				foreach (Relationship rel in node1.getRelationships())
				{
					rel.delete();
				}
				node1.delete();
				node2.delete();
				tx.success();
			}
			finally
			{
				tx.finish();
			}
		}

		private void assertPropertyEqual(PropertyContainer primitive, string key, string @value)
		{
			Transaction tx = getGraphDb().beginTx();
			try
			{
				assertEquals(@value, primitive.getProperty(key));
			}
			finally
			{
				tx.finish();
			}
		}

		private void assertRelationshipCount(Node node, int count)
		{
			Transaction tx = getGraphDb().beginTx();
			try
			{
				int actualCount = 0;
				foreach (Relationship rel in node.getRelationships())
				{
					actualCount++;
				}
				assertEquals(count, actualCount);
			}
			finally
			{
				tx.finish();
			}
		}
	}

}